﻿
//#if OPENGL
//#if MONOMAC
//using MonoMac.OpenGL;
//#elif WINDOWS || LINUX
//using OpenTK.Graphics.OpenGL;
//#elif GLES
//using OpenTK.Graphics.ES20;
//using TextureUnit = OpenTK.Graphics.ES20.All;
//using TextureTarget = OpenTK.Graphics.ES20.All;
//#endif
//#endif

#ifndef TextureCollection_h
#define TextureCollection_h

#include <System/String.h>
#include <System/Int32.h>
#include <System/Array.h>

#include "Texture.h"

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
			namespace Graphics
			{
				class TextureCollection sealed
				{
					private: /*readonly*/ GC_PTR<Riccsson::System::Array<GC_PTR<Texture>>> _textures;

			#if OPENGL
					private: readonly GC_PTR<Riccsson::System::Array<TextureTarget>> _targets;
			#endif

					private: int _dirty;

					public: /*internal*/ TextureCollection(int maxTextures)
					{
						_textures = new Riccsson::System::Array<GC_PTR<Texture>>(maxTextures);
						_dirty = Riccsson::System::Int32::MaxValue;
			#if OPENGL
						_targets = new TextureTarget[maxTextures];
			#endif
					}

					// TODO: Implement GET/SET methods instead.
					//public: GC_PTR<Texture> operator[](int index)
					//{
					//	get { return _textures[index]; }
					//	set
					//	{
					//		if (_textures[index] == value)
					//			return;
					//
					//		_textures[index] = value;
					//		_dirty |= 1 << index;
					//	}
					//}

					public: /*internal*/ void Clear()
					{
						_dirty = Riccsson::System::Int32::MaxValue;
					}

					/// <summary>
					/// Marks all texture slots as dirty.
					/// </summary>
					public: /*internal*/ void Dirty()
					{
						_dirty = Riccsson::System::Int32::MaxValue;
					}

					public: /*internal*/ void SetTextures(GC_PTR<GraphicsDevice> device)
					{
			#if !DIRECTX
						//Threading.EnsureUIThread();
						throw; // Implement Threading...
			#endif

						// Skip out if nothing has changed.
						if (_dirty == 0)
							return;

			#if DIRECTX
						// NOTE: We make the assumption here that the caller has
						// locked the d3dContext for us to use.
						var pixelShaderStage = device._d3dContext.PixelShader;
			#endif

						for (var i = 0; i < _textures->Length; i++)
						{
							var mask = 1 << i;
							if ((_dirty & mask) == 0)
								continue;

							var tex = _textures[i];
			#if OPENGL
							GL.ActiveTexture(TextureUnit.Texture0 + i);
							GraphicsExtensions.CheckGLError();

							// Clear the previous binding if the 
							// target is different from the new one.
							if (_targets[i] != 0 && (tex == null || _targets[i] != tex.glTarget))
							{
								GL.BindTexture(_targets[i], 0);
								GraphicsExtensions.CheckGLError();
							}

							if (tex != null)
							{
								_targets[i] = tex.glTarget;
								GL.BindTexture(tex.glTarget, tex.glTexture);
								GraphicsExtensions.CheckGLError();
							}
			#elif DIRECTX
							if (_textures[i] == null)
								pixelShaderStage.SetShaderResource(i, null);
							else
								pixelShaderStage.SetShaderResource(i, _textures[i].GetShaderResourceView());
			#endif

							_dirty &= ~mask;
							if (_dirty == 0)
								break;
						}

						_dirty = 0;
					}

				};
			}
		}
	}
}

#endif